import {
  Component,
  OnInit,
  ViewEncapsulation,
  ChangeDetectionStrategy,
  Input,
  ViewChild,
  ElementRef,
  ChangeDetectorRef,
  OnChanges,
  SimpleChanges,
  Output,
  EventEmitter,
  AfterViewInit,
} from '@angular/core';
import { findIndex as _findeIndex } from 'lodash';
import { DateService, I18NService, LvCalendarMode, LvConfig, StandardDate } from '../core/api';

@Component({
  selector: 'lv-calendar-panel',
  templateUrl: './calendar-panel.component.html',
  encapsulation: ViewEncapsulation.None,
  changeDetection: ChangeDetectionStrategy.OnPush,
  host: {
    class: 'lv-calendar-panel',
  },
})
export class CalendarPanelComponent implements OnInit, OnChanges, AfterViewInit {
  @Input() lvMode: LvCalendarMode = 'month';

  @Input('lvActiveDate') activeDate: StandardDate = new StandardDate();

  @ViewChild('yearContainer', { static: false }) yearContainer: ElementRef<any>;

  @ViewChild('monthContainer', { static: false }) monthContainer: ElementRef<any>;

  @Output() valueChange: EventEmitter<{ key: number; label: string; value: Date; isSelected: boolean }> =
    new EventEmitter();

  currentYear: number;
  currentMonth: number;
  yearTotal: number = 21; // 可选择的年份总数
  yearOffset: number = 10; // 可选择的年份前后数量范围：10年内
  language = LvConfig.language;
  years: Array<{ key: number; label: string; value: Date; isSelected: boolean }> = [];
  months: Array<{ key: number; label: string; value: Date; isSelected: boolean }> = [];

  constructor(
    public cdr: ChangeDetectorRef,
    public dateService: DateService,
    public i18n: I18NService,
  ) {}

  trackByIndex(index): any {
    return index;
  }

  ngAfterViewInit(): void {
    this.setPanelHighlightPosition();
  }

  /**
   * 获取选中项的index
   */
  getSelectedIndex(data: Array<{ key: number; label: string; value: Date; isSelected: boolean }>): number {
    return _findeIndex(data, (item) => item.isSelected);
  }

  ngOnInit(): void {
    this.currentYear = this.activeDate.getYear();
    this.currentMonth = this.activeDate.getMonth();

    this.setYears();
    this.setMonths();
  }

  ngOnChanges(changes: SimpleChanges): void {
    if (changes.activeDate) {
      this.currentYear = this.activeDate.getYear();
      this.currentMonth = changes.activeDate.currentValue.getMonth();
      this.setYears();
      this.setMonths();
    }
  }

  /**
   * 选择年份、月份
   * @param type 类型
   * @param item 选中项
   */
  updateDate(type, item): void {
    if (type === 'year') {
      this.currentYear = item.key;
    }

    if (type === 'month') {
      this.currentMonth = item.key;
    }

    this.setYears();
    this.setMonths();
    this.setPanelHighlightPosition();

    this.valueChange.emit(item);
  }

  setMonths(): void {
    this.months = [];

    const baseDate = new StandardDate(new Date('1970-1-1'));

    for (let mIndex = 0; mIndex < 12; mIndex++) {
      const date = new StandardDate(new StandardDate(baseDate.setYear(this.currentYear)).setMonth(mIndex));
      const monthLabel = this.dateService.format(date.localDate, 'MMM');
      const month = { key: mIndex, label: monthLabel, value: date.localDate, isSelected: this.currentMonth === mIndex };

      this.months.push(month);
    }
  }

  setYears(): void {
    this.years = [];

    const startYear = this.currentYear - this.yearOffset;
    const endYear = startYear + this.yearTotal;
    const baseDate = new StandardDate(new Date('1970-1-1'));

    for (let yIndex = startYear; yIndex < endYear; yIndex++) {
      const date = new StandardDate(new StandardDate(baseDate.setYear(yIndex)).setMonth(this.currentMonth));
      const yearLable = this.dateService.format(date.localDate, 'yyyy');
      const year = { key: yIndex, label: yearLable, value: date.localDate, isSelected: this.currentYear === yIndex };

      this.years.push(year);
    }
  }

  /**
   * 展开选择器时，分别定位到年、月选中项的位置
   */
  setPanelHighlightPosition(): void {
    if (!this.yearContainer) {
      return;
    }

    let contentDomes = [[this.yearContainer?.nativeElement, this.getSelectedIndex(this.years)]];
    this.lvMode === 'month' &&
      (contentDomes = [...contentDomes, ...[[this.monthContainer?.nativeElement, this.getSelectedIndex(this.months)]]]);

    contentDomes.forEach((item): void => {
      const contentDom = item[0];
      const index = item[1];

      // 缓冲滚动定位
      let duration = 120;

      const loop = (): void => {
        if (!contentDom) {
          return;
        }
        const li = contentDom?.querySelectorAll('li')[index];
        const _moveTo = li.offsetTop - contentDom.offsetTop;
        const _scrollTop = contentDom.scrollTop;
        const speed = ((_moveTo - _scrollTop) / duration) * 10;

        if (duration <= 0) {
          contentDom.scrollTop = _moveTo;
          return;
        }

        contentDom.scrollTop = _scrollTop + speed;

        if (_moveTo !== _scrollTop) {
          duration = duration - 5;
          requestAnimationFrame(loop);
        }
      };

      loop();
    });
  }
}
